package com.cx330.spring.ioc;

import com.cx330.spring.ioc.bean.Dog;
import com.cx330.spring.ioc.bean.Person;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;

import java.util.Map;

/**
 * 这个是主入口类，称为主程序类
 */
@SpringBootApplication
public class Spring01IocApplication {
    public static void main(String[] args) {
        // 1. 跑起一个Spring的应用，ApplicationContext：Spring应用上下文对象；IoC容器
        ConfigurableApplicationContext ioc = SpringApplication.run(Spring01IocApplication.class, args);
        System.out.println("ioc = " + ioc);

        System.out.println("=======================");

        // 2. 容器中装了哪些组件？获取到容器中所有组件的名字；Spring启动会有很多默认组件
        String[] names = ioc.getBeanDefinitionNames();
//        for (String name : names) {
//            System.out.println("name = " + name);
//        }

        // 4. 获取容器中的组件对象：精确获取某个组件
        // 组件的四大特性：（名字、类型）、对象、作用域
        // 组件名字全局唯一，组件名重复了，一定只会给容器中放一个最先声明的那个。
        /*
        小结：
        从容器中获取组件：
        1） 组件不存在，抛异常：NoSuchBeanDefinitionException
        2） 组件不唯一：
            按照类型只要一个：抛异常：NoUniqueBeanDefinitionException
            按照名字只要一个，精确获取到指定对象
            多个，返回所有组件的List集合
        3） 组件唯一存在，正确返回。
         */
        // 4.1 按照组件的名字获取对象
        Person person = (Person) ioc.getBean("person");
        System.out.println("对象 = " + person);

        // 4.2 按照组件类型获取对象
        Person bean = ioc.getBean(Person.class);
        System.out.println("bean = " + bean);

        // 4.3 按照组件类型获取这种类型的所有对象
        Map<String, Person> type = ioc.getBeansOfType(Person.class);
        System.out.println("type = " + type);

        // 4.4 按照类型 + 名字
        Person bean1 = ioc.getBean("person", Person.class);
        System.out.println("bean1 = " + bean1);

        // 5. 组件是单实例的
        /*
        创建时机：容器启动过程中就会创建组件对象
        单实例特性：所有组件默认是单例的，每次获取直接从容器中拿，容器提前会创建组件
         */
        Dog dog1 = ioc.getBean(Dog.class);
        System.out.println("dog1 = " + dog1);
        Dog dog2 = ioc.getBean(Dog.class);
        System.out.println("dog2 = " + dog2);
    }

    // 3. 给容器中注册一个自己的组件；容器中的每个组件都有自己的名字，方法名就是组件的名字
    @Bean
    public Person person() {
        Person person = new Person();
        person.setName("张三");
        person.setAge(20);
        person.setGender("男");
        return person;
    }

    @Bean
    public Dog dog() {
        return new Dog();
    }
}